home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / TARCHIV.ZIP / ASPI.PAS < prev    next >
Pascal/Delphi Source File  |  1995-01-27  |  20KB  |  765 lines

  1. { ASPI.TPU }
  2.  
  3. { Andreas Schiffler, U of S, 1994 }
  4.  
  5. { ASPI to SCSI-Tape (i.e. Exabyte) Interface Unit to provide most of the }
  6. { functions available for the EXB-8500 tape drive. }
  7.  
  8. { 286/287 instructions enabled for assembler code }
  9. {$G+}
  10.  
  11. Unit ASPI;
  12.  
  13. Interface
  14.  
  15. Uses Dos, Crt;
  16.  
  17. Const
  18.  
  19.   { Communication with ASPI over a data-block (SRB): }
  20.   { |---------64-------------|------6/10-------|--------- N ----------| }
  21.   {       ASPI-command          SCSI-Command      from Device (sense)
  22.  
  23.   { Field lengths }
  24.   ASPIBlockLength      = 64;
  25.   CommandBlockLength   = 6;
  26.   SenseBlockLength     = 29;
  27.   SRBBlockLength       = ASPIBlockLength+CommandBlockLength+SenseBlockLength+4;
  28.  
  29.   { Field locations }
  30.   CommandLocation      = ASPIBlockLength;
  31.   SenseLocation        = ASPIBlockLength+CommandBlockLength;
  32.  
  33.   { Local data buffer }
  34.   DataBufferSize       = 256;
  35.  
  36. Type
  37.      PDataBuffer = ^TDataBuffer;
  38.      TDataBuffer = Array [0..(DataBufferSize-1)] of Byte;
  39.  
  40.      { These values are defined after a call to INQUIRY. }
  41.      { }
  42.      TapeInfo = Record
  43.                  Valid      : Boolean;
  44.                  HostNumber : Byte;
  45.                  Target     : Byte;
  46.                  Host       : String[32];
  47.                  Device     : String[16];
  48.                  Vendor     : String[8];
  49.                  Product    : String[16];
  50.                  Revision   : String[4];
  51.                  Serial     : String[10];
  52.                 End;
  53.  
  54.      { ERROR indicates any kind of status which requires attention. }
  55.      { WRITE_PROTECTION_ON is only defined when ERROR is false.}
  56.      { }
  57.      TapeStatus = Record
  58.                    Error    : Boolean;
  59.                    ASPI     : String[60];
  60.                    Host     : String[60];
  61.                    Target   : String[60];
  62.                    Sense    : String[60];
  63.                    SenseExt : String[60];
  64.                    FilemarkDetected : Boolean;
  65.                    TapeNotPresent   : Boolean;
  66.                    BeginningOfTape  : Boolean;
  67.                    EndOfTape        : Boolean;
  68.                    WriteProtectOn   : Boolean;
  69.                   End;
  70.  
  71.      SRBType = Array [0..(SRBBlockLength-1)] Of Byte;
  72.  
  73.      PASPITape = ^ASPITape;
  74.      ASPITape = Object
  75.                  SRB        : SRBType;
  76.                  HSeg_Data,
  77.                  LSeg_Data,
  78.                  HOfs_Data,
  79.                  LOfs_Data  : Byte;
  80.                  SenseStart : Byte;
  81.                  DataBuffer : PDataBuffer;
  82.                  TarBlock   : Byte;
  83.                  Info       : TapeInfo;
  84.                  Status     : TapeStatus;
  85.  
  86.                  Constructor Init (TargetNumber : Byte);
  87.                  Destructor  Done;
  88.                  Procedure   CallASPI;
  89.                  Procedure   Inquiry;
  90.                  Procedure   RequestSense;
  91.                  Procedure   TestUnitReady;
  92.                  Procedure   ParseStatus;
  93.                  Procedure   ModeSelect(BufferSize : Word);
  94.                  Procedure   ReadData(Buffer : Pointer; BufferSize : Word);
  95.                  Procedure   WriteData(Buffer : Pointer; BufferSize : Word);
  96.                  Function    TapePosition : Longint;
  97.                  Procedure   LocateTape (Location : Longint);
  98.                  Procedure   ASPIReset;
  99.                  Procedure   WriteFilemark (Number : Byte);
  100.                  Procedure   SpaceFilemark (Spacing : Longint);
  101.                  Procedure   GotoEnd;
  102.                  Procedure   Rewind;
  103.                  Procedure   Unload;
  104.                  Procedure   Load;
  105.                  Procedure   Erase;
  106.                 End;
  107.  
  108. Implementation
  109.  
  110. Var
  111.  GlobalSRB        : SRBType;     { THE ASPI Command Block }
  112.  LockSRB          : Boolean;     { Sync. flag for multiple objects }
  113.  
  114. { Utility routines }
  115. { ================ }
  116.  
  117. { ASPITape routines }
  118. { ================= }
  119.  
  120. Constructor ASPITape.Init (TargetNumber : Byte);
  121.  
  122. Begin
  123. { Initialize variables }
  124.  Info.Valid      := False;
  125.  Info.Target     := TargetNumber;
  126.  Info.HostNumber := 0;
  127.  Info.Host       := '?';
  128.  Info.Vendor     := '?';
  129.  Info.Product    := '?';
  130.  Info.Revision   := '?';
  131.  Info.Serial     := '?';
  132.  Info.Device     := '?';
  133.  Status.Error    := False;
  134.  Status.ASPI     := '?';
  135.  Status.Host     := '?';
  136.  Status.Target   := '?';
  137.  Status.Sense    := '?';
  138.  Status.SenseExt := '?';
  139.  Status.FilemarkDetected := False;
  140.  Status.TapeNotPresent   := False;
  141.  Status.BeginningOfTape  := False;
  142.  Status.EndOfTape        := False;
  143.  Status.WriteProtectOn   := False;
  144.  
  145.  New(DataBuffer);                         { Create and Init data buffer }
  146.  LSeg_Data := Lo(Seg(DataBuffer^));
  147.  HSeg_Data := Hi(Seg(DataBuffer^));
  148.  LOfs_Data := Lo(Ofs(DataBuffer^));
  149.  HOfs_Data := Hi(Ofs(DataBuffer^));
  150.  FillChar (DataBuffer^[0],DataBufferSize,0);
  151. End;
  152.  
  153. Destructor ASPITape.Done;
  154. Begin
  155.  Dispose (DataBuffer);
  156. End;
  157.  
  158. Procedure ASPITape.CallASPI;
  159. Const
  160.  Message   : Array [0..9] of Char = ('S','C','S','I','M','G','R','$',#0,#0);
  161. Var
  162.  ASPIEntry : Array [0..3] of Byte;
  163.  Timeout   : Longint;
  164.  Manager   : Byte;
  165. Begin
  166.  { Set Manager flag }
  167.  Manager := 0;
  168.  { Wait until GlobalSRB gets unlocked. }
  169.  While LockSRB Do ;
  170.  { Lock SRB transfer to global data and execute. }
  171.  LockSRB := True;
  172.  Move(SRB,GlobalSRB,SizeOf(SRBType));
  173.  Asm
  174.   Push DS
  175.  
  176.   mov ax,$3d00
  177.   lea dx,Message
  178.   int $21
  179.   jc @NoManager
  180.  
  181.   push ax
  182.   mov bx,ax
  183.   mov ax,$4402
  184.   lea dx,ASPIEntry
  185.   mov cx,4
  186.   int $21
  187.  
  188.   mov ah,$3e
  189.   pop bx
  190.   int $21
  191.  
  192.   push ds
  193.   lea bx,[GlobalSRB]
  194.   push bx
  195.   lea bx,ASPIEntry
  196.   call dword ptr [bx]
  197.   add sp,4
  198.   mov al,1;
  199.   mov manager,al
  200.  
  201.   @NoManager:
  202.   Pop DS
  203.  End;
  204.  { Check if a ASPI Manager was present }
  205.  IF (Manager=1) Then Begin
  206.   { Wait for command to finish - timeout after a 4 hours.       }
  207.   { This will give time for slow commands liek ERASE to finish. }
  208.   Timeout := 0;
  209.   Repeat
  210.    INC(Timeout);
  211.    Delay (10);
  212.   Until ((GlobalSRB[1]<>0) OR (Timeout=4*60*60*100));
  213.   If Timeout=4*60*60*100 Then GlobalSRB[1]:=$FF;  { report Timeout Error }
  214.  End Else Begin
  215.   GlobalSRB[1]:=$FE; { No ASPI Manager Error }
  216.   Info.Valid := False;
  217.  End;
  218.  { Transfer to local buffer and unlock. }
  219.  Move (GlobalSRB,SRB,SizeOf(SRBType));
  220.  LockSRB := False;
  221.  { Check for request sense command and any errors from that }
  222.  If (SRB[0]=2) AND (SRB[64]=$03) AND ((DataBuffer^[2] AND $0F)<>0) Then Begin
  223.   { Transfer data to SRB and set flag to check }
  224.   SRB[25] := $02;
  225.   Move (DataBuffer^,SRB[70],29);
  226.  End;
  227.  { Determine Sense Location }
  228.  SenseStart := 64+SRB[23];
  229.  { Determine error status from ASPI, Host and Sense area }
  230.  Status.Error := (SRB[1]<>1) OR (SRB[24]<>0) OR (SRB[25]<>0) OR ((SRB[SenseStart+2] AND $0F)<>0);
  231. End;
  232.  
  233. { Call this whenever the ERROR is set to fill the STATUS fields. }
  234. { }
  235. Procedure ASPITape.ParseStatus;
  236. Begin
  237.  If SRB[1]=$FE Then Begin
  238.   Status.ASPI := 'No ASPI-Manager present';
  239.   Status.Host := '?';
  240.   Status.Target := '?';
  241.   Status.Sense := '?';
  242.   Status.SenseExt := '?';
  243.   Status.FilemarkDetected := False;
  244.   Status.TapeNotPresent   := False;
  245.   Status.BeginningOfTape  := False;
  246.   Status.WriteProtectOn   := False;
  247.   Status.EndOfTape        := False;
  248.  End Else Begin
  249.   { Get all the information }
  250.   RequestSense;
  251.   { Determine status }
  252.   Case SRB[1] of
  253.      0: Status.ASPI := 'SCSI request in progress';
  254.      1: Status.ASPI := 'SCSI request completed without error';
  255.      2: Status.ASPI := 'SCSI request aborted by host';
  256.      4: Status.ASPI := 'SCSI request completed with error';
  257.    $80: Status.ASPI := 'SCSI request invalid';
  258.    $81: Status.ASPI := 'Invalid host adapter number';
  259.    $82: Status.ASPI := 'SCSI adapter not installed';
  260.    $FF: Status.ASPI := 'SCSI request in progress, timeout';
  261.   End;
  262.   Case SRB[24] of
  263.    $00: Status.Host := 'Host adapter did not detect any error';
  264.    $11: Status.Host := 'Selection timeout';
  265.    $12: Status.Host := 'Data overrun/underrun';
  266.    $13: Status.Host := 'Unexpected bus free';
  267.    $14: Status.Host := 'Target bus phase sequence failure';
  268.   End;
  269.    Case SRB[25] of
  270.    $00: Status.Target := 'No/Good target status';
  271.    $02: Status.Target := 'Sense data available';
  272.    $04: Status.Target := 'Condition met';
  273.    $08: Status.Target := 'Specified target busy';
  274.    $14: Status.Target := 'Intermediate condition met';
  275.    $18: Status.Target := 'Reservation conflict';
  276.    $22: Status.Target := 'Command terminated';
  277.    $28: Status.Target := 'Queue full';
  278.   End;
  279.   If SRB[25]=$02 Then Begin
  280.     { Sense available }
  281.    Case (SRB[SenseStart+2] AND $0F) of
  282.     0: Begin
  283.         Status.Sense := 'No Sense';
  284.         Case SRB[82] of
  285.          $00: Case SRB[83] of
  286.                $01: Status.SenseExt := 'Filemark encountered during read';
  287.                $02: Status.SenseExt := 'LEOT encountered';
  288.                $04: Status.SenseExt := 'LBOT detected';
  289.               End;
  290.          $3b: Status.SenseExt := 'Tape position error at beginning';
  291.         End;
  292.        End;
  293.     1: Begin
  294.         Status.Sense := 'Recovered Error';
  295.         Status.SenseExt := '';
  296.        End;
  297.     2: Begin
  298.         Status.Sense := 'Not Ready';
  299.         Case SRB[SenseStart+12] of
  300.          $04: Case SRB[SenseStart+13] of
  301.                $00: Status.SenseExt := 'Tape not present';
  302.                $01: Status.SenseExt := 'Tape loading or rewinding';
  303.                $02: Status.SenseExt := 'Tape motion command required';
  304.                $03: Status.SenseExt := 'Unrecoverable hardware error';
  305.               End;
  306.          $3A: Status.SenseExt := 'Tape not present';
  307.         End;
  308.        End;
  309.     3: Begin
  310.         Status.Sense := 'Medium Error';
  311.         Case SRB[SenseStart+12] of
  312.          $3b: Case SRB[SenseStart+13] of
  313.                $00: Status.SenseExt := 'Position error';
  314.                $02: Status.SenseExt := 'Position error at end';
  315.               End;
  316.          $00: Status.SenseExt := 'Undetermined error';
  317.          $03: Status.SenseExt := 'Excessive write errors';
  318.          $09: Status.SenseExt := 'Tracking error';
  319.          $0C: Status.SenseExt := 'Hard write error';
  320.          $11: Status.SenseExt := 'Hard read error';
  321.         End;
  322.        End;
  323.     4: Begin
  324.         Status.Sense := 'Hardware Error';
  325.         Case SRB[SenseStart+12] of
  326.          $40: Case SRB[83] of
  327.                $80: Status.SenseExt := 'DPATH error';
  328.                $81: Status.SenseExt := 'DPATH underrun';
  329.               End;
  330.          $00: Status.SenseExt := 'Undetermined';
  331.          $09: Status.SenseExt := 'Track follow error';
  332.          $44: Status.SenseExt := 'Internal failure/Software hang';
  333.         End;
  334.        End;
  335.     5: Begin
  336.         Status.Sense := 'Illegal Request';
  337.         Case SRB[SenseStart+12] of
  338.          $1A: Status.SenseExt := 'Parameter list length error';
  339.          $20: Status.SenseExt := 'Illegal CDB code';
  340.          $24: Status.SenseExt := 'Invalid CDB field';
  341.          $25: Status.SenseExt := 'LUN not supported';
  342.          $26: Status.SenseExt := 'Invalid parameter';
  343.          $3D: Status.SenseExt := 'LUN invalid';
  344.          $81: Status.SenseExt := 'Fixed mode mismatch';
  345.         End;
  346.        End;
  347.     6: Begin
  348.         Status.Sense := 'Unit Attention';
  349.         Case SRB[SenseStart+12] of
  350.          $28: Status.SenseExt := 'Media has been changed';
  351.          $29: Status.SenseExt := 'Reset has occured';
  352.          $2A: Status.SenseExt := 'Mode select has been changed';
  353.          $3F: Status.SenseExt := 'New microcode loaded';
  354.         End;
  355.        End;
  356.     7: Begin
  357.         Status.Sense := 'Data Protect';
  358.         Status.SenseExt := 'The tape is write protected';
  359.        End;
  360.     8: Begin
  361.         Status.Sense := 'Blank Check';
  362.         Status.SenseExt := 'End of data encountered on read';
  363.        End;
  364.     9: Begin
  365.         Status.Sense := 'EXABYTE specific error';
  366.         Status.SenseExt := '';
  367.        End;
  368.    10: Begin
  369.         Status.Sense := 'Copy Aborted';
  370.         Status.SenseExt := '';
  371.        End;
  372.    11: Begin
  373.         Status.Sense := 'Aborted Command';
  374.         Case SRB[SenseStart+12] of
  375.          $45: Status.SenseExt := 'Reselect failed';
  376.          $47: Status.SenseExt := 'SCSI bus failure during write';
  377.          $48: Status.SenseExt := 'Initiator detected error';
  378.          $49: Status.SenseExt := 'Invalid message recieved';
  379.         End;
  380.        End;
  381.    13: Begin
  382.         Status.Sense := 'Volume Overflow';
  383.         Status.SenseExt := 'PEOT encountered during write';
  384.        End;
  385.    End;
  386.    { Set booleans }
  387.    Status.FilemarkDetected := ((SRB[SenseStart+ 2] AND $80)<>0);
  388.    Status.TapeNotPresent   := ((SRB[SenseStart+19] AND $02)<>0);
  389.    Status.BeginningOfTape  := ((SRB[SenseStart+19] AND $01)<>0);
  390.    Status.WriteProtectOn   := ((SRB[SenseStart+20] AND $20)<>0);
  391.    Status.EndOfTape        := ((SRB[SenseStart+21] AND $04)<>0);
  392.   End Else Begin
  393.    { Sense not available }
  394.    Status.Sense := '';
  395.    Status.SenseExt := '';
  396.   End;
  397.  End;
  398. End;
  399.  
  400. { Used by ParseStatus. }
  401. { }
  402. Procedure ASPITape.RequestSense;
  403. Begin
  404.  { ASPI Setup for sense inquiry }
  405.  FillChar (SRB,SizeOf(SRB),0);
  406.  SRB[ 0]:=2;
  407.  SRB[ 8]:=Info.Target;
  408.  SRB[10]:=29;
  409.  SRB[15]:=LOfs_Data;
  410.  SRB[16]:=HOfs_Data;
  411.  SRB[17]:=LSeg_Data;
  412.  SRB[18]:=HSeg_Data;
  413.  SRB[23]:=6;
  414.  SRB[64]:=$03;
  415.  SRB[68]:=29;
  416.  { Execute }
  417.  CallASPI;
  418. End;
  419.  
  420. { Determine host and tape parameters, thus initializing the INFO field. }
  421. { }
  422. Procedure ASPITape.Inquiry;
  423. Begin
  424.  { ASPI Setup for host inquiry }
  425.  FillChar (SRB,SizeOf(SRB),0);
  426.  SRB[ 0]:=0;
  427.  SRB[ 8]:=Info.Target;
  428.  { Execute }
  429.  CallASPI;
  430.  If Status.Error Then ParseStatus;
  431.  { Extract information }
  432.  Move (SRB[10],Info.Host[1],32);
  433.  Info.Host[0]:=Chr(32);
  434.  Info.HostNumber := SRB[8];
  435.  { Setup for device inquiry }
  436.  FillChar (SRB,SizeOf(SRB),0);
  437.  SRB[ 0]:=1;
  438.  SRB[ 8]:=Info.Target;
  439.  { Execute }
  440.  CallASPI;
  441.  { Extract Information }
  442.  Info.Valid := False;
  443.  If Status.Error Then Begin
  444.   ParseStatus;
  445.   Info.Device := 'Unknown';
  446.  End Else
  447.   Case SRB[10] of
  448.    0:  Begin Info.Device:='Disk'; Info.Valid := True; End;
  449.    1:  Begin Info.Device:='Tape'; Info.Valid := True; End;
  450.    2:  Begin Info.Device:='Printer'; Info.Valid := True; End;
  451.    3:  Begin Info.Device:='Processor'; Info.Valid := True; End;
  452.    4:  Begin Info.Device:='WORM'; Info.Valid := True; End;
  453.    5:  Begin Info.Device:='CD-ROM'; Info.Valid := True; End;
  454.    6:  Begin Info.Device:='Scanner'; Info.Valid := True; End;
  455.    7:  Begin Info.Device:='Optical Memory'; Info.Valid := True; End;
  456.    8:  Begin Info.Device:='Medium Changer'; Info.Valid := True; End;
  457.    9:  Begin Info.Device:='Communication'; Info.Valid := True; End;
  458.   Else
  459.    Info.Device := 'Unknown';
  460.   End;
  461.  If Info.Valid Then Begin
  462.   { ASPI Setup for specific inquiry }
  463.   FillChar (SRB,SizeOf(SRB),0);
  464.   SRB[ 0]:=2;
  465.   SRB[ 8]:=Info.Target;
  466.   SRB[10]:=106;
  467.   SRB[15]:=LOfs_Data;
  468.   SRB[16]:=HOfs_Data;
  469.   SRB[17]:=LSeg_Data;
  470.   SRB[18]:=HSeg_Data;
  471.   SRB[23]:=6;
  472.   SRB[64]:=$12;
  473.   SRB[68]:=106;
  474.   { Execute }
  475.   CallASPI;
  476.   { Extract product information to Pascal strings }
  477.   Move (DataBuffer^[8],Info.Vendor[1],8);
  478.   Info.Vendor[0]:=#8;
  479.   Move (DataBuffer^[16],Info.Product[1],16);
  480.   Info.Product[0]:=#16;
  481.   Move (DataBuffer^[32],Info.Revision[1],4);
  482.   Info.Revision[0]:=#4;
  483.   Move (DataBuffer^[96],Info.Serial[1],10);
  484.   Info.Serial[0]:=#10;
  485.  End;
  486. End;
  487.  
  488. { This routine is used to prepare the tape drive for a "good" status.}
  489. { Keep calling this routine until ERROR is false. }
  490. { }
  491. Procedure ASPITape.TestUnitReady;
  492. Begin
  493.  FillChar (SRB,SizeOf(SRB),0);
  494.  SRB[ 0]:=2;
  495.  SRB[ 8]:=Info.Target;
  496.  SRB[23]:=6;
  497.  SRB[64]:=0;
  498.  { Execute }
  499.  CallASPI;
  500. End;
  501.  
  502. { Set the tape with current 'BlockSize' and use buffered-mode writes. }
  503. { }
  504. Procedure ASPITape.ModeSelect (BufferSize : Word);
  505. Begin
  506.  { ASPI Setup for Mode Select }
  507.  FillChar (SRB,SizeOf(SRB),0);
  508.  SRB[ 0]:=2;
  509.  SRB[ 8]:=Info.Target;
  510.  SRB[10]:=12;
  511.  SRB[15]:=LOfs_Data;
  512.  SRB[16]:=HOfs_Data;
  513.  SRB[17]:=LSeg_Data;
  514.  SRB[18]:=HSeg_Data;
  515.  SRB[23]:=6;
  516.  SRB[64]:=$15;
  517.  SRB[65]:=$10;
  518.  SRB[68]:=12;
  519.  FillChar (DataBuffer^[0],12,0);
  520.  DataBuffer^[2]:=$10;  { Buffered mode }
  521.  DataBuffer^[3]:=8;
  522.  DataBuffer^[10]:=Hi(BufferSize);
  523.  DataBuffer^[11]:=Lo(BufferSize);
  524.  { Execute }
  525.  CallASPI;
  526. End;
  527.  
  528. { Write the block in 'Buffer' to tape. }
  529. { }
  530. Procedure ASPITape.WriteData (Buffer : Pointer; BufferSize : Word);
  531. Begin
  532.  { ASPI Setup for Block Write }
  533.  FillChar (SRB,SizeOf(SRB),0);
  534.  SRB[ 0]:=2;
  535.  SRB[ 8]:=Info.Target;
  536.  SRB[10]:=Lo(BufferSize);
  537.  SRB[11]:=Hi(BufferSize);
  538.  SRB[15]:=Lo(Ofs(Buffer^));
  539.  SRB[16]:=Hi(Ofs(Buffer^));
  540.  SRB[17]:=Lo(Seg(Buffer^));
  541.  SRB[18]:=Hi(Seg(Buffer^));
  542.  SRB[23]:=6;
  543.  
  544.  SRB[64]:=$0A;
  545.  SRB[65]:=$01;
  546.  SRB[68]:=1;       { Write one block of size set in MODE SELECT }
  547.  { Execute }
  548.  CallASPI;
  549.  { Reset TarBlock count }
  550.  TarBlock := 0;
  551. End;
  552.  
  553. { Reads the next block of 'BufferSize' and stores it in 'Buffer'. }
  554. { }
  555. Procedure ASPITape.ReadData(Buffer : Pointer; BufferSize : Word);
  556. Begin
  557.  { ASPI Setup for Block Read }
  558.  FillChar (SRB,SizeOf(SRB),0);
  559.  SRB[ 0]:=2;
  560.  SRB[ 8]:=Info.Target;
  561.  SRB[10]:=Lo(BufferSize);
  562.  SRB[11]:=Hi(BufferSize);
  563.  SRB[15]:=Lo(Ofs(Buffer^));
  564.  SRB[16]:=Hi(Ofs(Buffer^));
  565.  SRB[17]:=Lo(Seg(Buffer^));
  566.  SRB[18]:=Hi(Seg(Buffer^));
  567.  SRB[23]:=6;
  568.  
  569.  SRB[64]:=$08;
  570.  SRB[65]:=$01;
  571.  SRB[68]:=1;          { Read one block of size set in MODE SELECT }
  572.  { Execute }
  573.  CallASPI;
  574. End;
  575.  
  576. { Returns tape position in terms of logical blocks. }
  577. { }
  578. Function ASPITape.TapePosition : Longint;
  579. Type
  580.   B4 = Array [0..4] Of Byte;
  581. Var
  582.   L  : Longint;
  583.   LA : B4 Absolute L;
  584. Begin
  585.  { ASPI Setup for Position Inquiry }
  586.  FillChar (SRB,SizeOf(SRB),0);
  587.  SRB[ 0]:=2;
  588.  SRB[ 8]:=Info.Target;
  589.  SRB[10]:=20;
  590.  SRB[15]:=LOfs_Data;
  591.  SRB[16]:=HOfs_Data;
  592.  SRB[17]:=LSeg_Data;
  593.  SRB[18]:=HSeg_Data;
  594.  SRB[23]:=10;
  595.  
  596.  SRB[64]:=$34;
  597.  { Execute }
  598.  CallASPI;
  599.  { Extract Information }
  600.  If ((DataBuffer^[0] And 4)<>0) Then
  601.   TapePosition := -1                         { Position unknown }
  602.  Else Begin
  603.   LA[0] := DataBuffer^[7];
  604.   LA[1] := DataBuffer^[6];
  605.   LA[2] := DataBuffer^[5];
  606.   LA[3] := DataBuffer^[4];
  607.   TapePosition := L;
  608.  End;
  609. End;
  610.  
  611. { Locate to a specific logical block. Any direction works. }
  612. { }
  613. Procedure ASPITape.LocateTape (Location : Longint);
  614. Begin
  615.  { ASPI Setup for Set Position }
  616.  FillChar (SRB,SizeOf(SRB),0);
  617.  SRB[ 0]:=2;
  618.  SRB[ 8]:=Info.Target;
  619.  SRB[23]:=10;
  620.  
  621.  SRB[64]:=$2B;
  622.  SRB[67]:= ((Location SHR 24) AND $8F);
  623.  SRB[68]:= ((Location SHR 16) AND $FF);
  624.  SRB[69]:= ((Location SHR 8) AND $FF);
  625.  SRB[70]:= (Location And $FF);
  626.  { Execute }
  627.  CallASPI;
  628. End;
  629.  
  630. { Resets ASPI and the device connected to it. }
  631. { Causes a rewind. }
  632. { }
  633. Procedure ASPITape.ASPIReset;
  634. Begin
  635.  { ASPI Setup for Reset }
  636.  FillChar (SRB,SizeOf(SRB),0);
  637.  SRB[ 0]:=4;
  638.  SRB[ 8]:=Info.Target;
  639.  
  640.  { Execute }
  641.  CallASPI;
  642. End;
  643.  
  644. { Write 'Number' filemarks to the tape }
  645. { }
  646. Procedure ASPITape.WriteFilemark (Number : Byte);
  647. Begin
  648.  { ASPI Setup for Write Filemark }
  649.  FillChar (SRB,SizeOf(SRB),0);
  650.  SRB[ 0]:=2;
  651.  SRB[ 8]:=Info.Target;
  652.  SRB[23]:=6;
  653.  
  654.  SRB[64]:=$10;
  655.  SRB[68]:=Number;
  656.  
  657.  { Execute }
  658.  CallASPI;
  659. End;
  660.  
  661. { Space over 'Spacing' filemarks }
  662. { }
  663. Procedure ASPITape.SpaceFilemark (Spacing : Longint);
  664. Begin
  665.  { ASPI Setup for Space Filemark }
  666.  FillChar (SRB,SizeOf(SRB),0);
  667.  SRB[ 0]:=2;
  668.  SRB[ 8]:=Info.Target;
  669.  SRB[23]:=6;
  670.  
  671.  SRB[64]:=$11;
  672.  SRB[65]:=1;
  673.  SRB[66]:=((Spacing SHR 16) AND $FF);
  674.  SRB[67]:=((Spacing SHR 8) AND $FF);
  675.  SRB[68]:=(Spacing AND $FF);
  676.  
  677.  { Execute }
  678.  CallASPI;
  679. End;
  680.  
  681. { Set the tape to the 'End of Data'-position }
  682. { }
  683. Procedure ASPITape.GotoEnd;
  684. Begin
  685.  { ASPI Setup for Spacing to EOD }
  686.  FillChar (SRB,SizeOf(SRB),0);
  687.  SRB[ 0]:=2;
  688.  SRB[ 8]:=Info.Target;
  689.  SRB[23]:=6;
  690.  
  691.  SRB[64]:=$11;
  692.  SRB[65]:=3;
  693.  
  694.  { Execute }
  695.  CallASPI;
  696. End;
  697.  
  698. { Rewinds the tape to the begining. }
  699. { }
  700. Procedure ASPITape.Rewind;
  701. Begin
  702.  { ASPI Setup for Rewind }
  703.  FillChar (SRB,SizeOf(SRB),0);
  704.  SRB[ 0]:=2;
  705.  SRB[ 8]:=Info.Target;
  706.  SRB[23]:=6;
  707.  
  708.  SRB[64]:=$01;
  709.  
  710.  { Execute }
  711.  CallASPI;
  712. End;
  713.  
  714. Procedure ASPITape.Unload;
  715. Begin
  716.  { ASPI Setup for Unload }
  717.  FillChar (SRB,SizeOf(SRB),0);
  718.  SRB[ 0]:=2;
  719.  SRB[ 8]:=Info.Target;
  720.  SRB[23]:=6;
  721.  
  722.  SRB[64]:=$1B;
  723.  SRB[68]:=0;
  724.  
  725.  { Execute }
  726.  CallASPI;
  727. End;
  728.  
  729. Procedure ASPITape.Erase;
  730. Begin
  731.  { ASPI Setup for Erase }
  732.  FillChar (SRB,SizeOf(SRB),0);
  733.  SRB[ 0]:=2;
  734.  SRB[ 8]:=Info.Target;
  735.  SRB[23]:=6;
  736.  
  737.  SRB[64]:=$19;
  738.  SRB[65]:=1;
  739.  
  740.  { Execute }
  741.  CallASPI;
  742. End;
  743.  
  744. Procedure ASPITape.Load;
  745. Begin
  746.  { ASPI Setup for Load }
  747.  FillChar (SRB,SizeOf(SRB),0);
  748.  SRB[ 0]:=2;
  749.  SRB[ 8]:=Info.Target;
  750.  SRB[23]:=6;
  751.  
  752.  SRB[64]:=$1B;
  753.  SRB[68]:=1;
  754.  
  755.  { Execute }
  756.  CallASPI;
  757. End;
  758.  
  759. { ============================================================ }
  760.  
  761. { Initialisation code }
  762. Begin
  763.  LockSRB := False;
  764. End.
  765.